/* mcSoup.cpp
 *
 * --
 * Copyright (c) 2012, Christophe Huriaux
 * Distributed under the terms of the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * --
 */

#include <iostream>
#include <sstream>
#include <cerrno>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <config.h>
#include <socket/McSocket.h>

#include <packet/McPacket.h>
#include <packet/packets.h>

#include <graphics/GLWindow.h>
#include <graphics/GLScene.h>
#include <graphics/GLVertexArray.h>
#include <graphics/GLVertexArrayColor.h>
#include <graphics/GLVertexData.h>
#include <graphics/GLVertexDataLocal.h>
#include <graphics/GLTexture.h>
#include <graphics/GLTextureManager.h>
#include <graphics/GLStringFactory.h>
#include <graphics/SDLSurface.h>
#include <utils/glvector.h>
#include <utils/GLInfo.h>
#include <debug/logger.h>
#include <textures.h>

using logg::endl;

class GLTest : public GLScene
{
	GLVertexDataLocal<vector3d> vertices;
	GLVertexDataLocal<vector3d> colors;
	GLVertexArrayColor<vector3d, vector3d> vertexArray;
	GLStringFactory s;
	time_t tref, tcount;
	int fps;

public:
	GLTest() : vertices(8, 3), colors(8, 3),
		vertexArray(&vertices, &colors),
		s(10, 10, "0 fps"), fps(0)
	{
		vertices.init(
			{
				{ 2 , 2 , 2 },
				{ 2 , 2 , 3 },
				{ 2 , 3 , 3 },
				{ 2 , 3 , 2 },
				{ 3 , 2 , 2 },
				{ 3 , 2 , 3 },
				{ 3 , 3 , 3 },
				{ 3 , 3 , 2 }
			}
		);

		colors.init(
			{ //  R  G  B
				{ 0, 0, 0 },
				{ 0, 0, 1 },
				{ 0, 1, 1 },
				{ 0, 1, 0 },
				{ 1, 0, 0 },
				{ 1, 0, 1 },
				{ 1, 1, 1 },
				{ 1, 1, 0 }
			}
		);

		time(&tref);
	}

private:
	void draw()
	{
		static unsigned int indexes[] =
		{ 0, 1, 2, 3,
		  7, 6, 5, 4,
		  1, 5, 6, 2,
		  4, 0, 3, 7,
		  4, 5, 1, 0,
		  3, 2, 6, 7 };

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		updatePerspective();
		glEnable(GL_DEPTH_TEST);
		//glEnable(GL_LIGHTING);
		glEnable(GL_CULL_FACE);
		glEnable(GL_TEXTURE_2D);

		updateCamera();

		glBegin(GL_QUADS);
			glColor3ub(150, 150, 150);
			glVertex3d(-100, 0, -100);
			glVertex3d(-100, 0, 100);
			glVertex3d(100, 0, 100);
			glVertex3d(100, 0, -100);
		glEnd();
		glBegin(GL_LINES);
			glColor3ub(0, 0, 255);
			glVertex3d(1, 1, 1);
			glVertex3d(1, 1, 20);

			glColor3ub(255, 0, 0);
			glVertex3d(1, 1, 1);
			glVertex3d(20, 1, 1);

			glColor3ub(0, 255, 0);
			glVertex3d(1, 1, 1);
			glVertex3d(1, 20, 1);
		glEnd();

		glColor3ub(255, 255, 255);

		vertexArray.drawIndexed(GL_QUADS, sizeof(indexes) / sizeof(unsigned int), indexes);

		// 2D Context
		glDisable(GL_DEPTH_TEST);
		//glEnable(GL_LIGHTING);
		glDisable(GL_CULL_FACE);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluOrtho2D(0, 640, 0, 480);

		// FPS display
		fps++;
		time(&tcount);
		if (difftime(tcount, tref) >= 1)
		{
			char fpsC[16];
			sprintf(fpsC, "%d fps", fps);
			s.setString(fpsC);
			time(&tref);
			fps = 0;
		}
		s.display();
		glFlush();
	}

	void drawCube(double x, double y, double z, double c)
	{
		glBegin(GL_LINES);
			glVertex3d(x, y, z);
			glVertex3d(x, y, z+c);
			glVertex3d(x, y, z+c);
			glVertex3d(x+c, y, z+c);
			glVertex3d(x+c, y, z+c);
			glVertex3d(x+c, y, z);
			glVertex3d(x, y, z);
		glEnd();
	}
};

int main() {
	Logger::get().setLogMask(logg::VERBOSE);

	flogg(info) << "mcSoup " << PACKAGE_STRING << logg::endl;

	// Textures
	flogg(info) << "Loading textures ..." << logg::endl;

	GLTextureManager::getInstance().setTexture(McTexture::FONT,
		new GLTexture(SDLSurface::loadFromFile("data/img/font.png"), 8, 8));

	GLWindow w("mcSoup " PACKAGE_STRING, 640, 480, 32);
	GLTest s;
	GLCamera c;

	s.setPerspective(70, (double)640/480, 1, 1000);
	c.setPosition(0, 1.6, 0);
	c.setVertical(0, 1, 0);
	c.setTheta(0);
	c.setPhi(0);

	s.setCamera(&c);
	w.setScene(&s);
	w.open();

	while (w.isAlive())
	{
		if (w.keyState()[SDLK_z])
			s.setFOVy(s.getFOVy() + 1);

		if (w.keyState()[SDLK_s])
			s.setFOVy(s.getFOVy() - 1);

		if (w.keyState()[SDLK_a])
		{
			w.setHeight(640);
			s.setPerspective(70, (double)640/640, 1, 1000);
		}

		if (w.hasMouseMoved())
		{
			c.setPhi(c.getPhi()+w.mouseMoveY()*-.1);
			c.setTheta(c.getTheta()+w.mouseMoveX()*.1);
		}
		usleep(10000);
	};

	/*
	McSocket s("blaiseminecraft.dyndns.org", 25565);
	if (s.getSocket().resolve() != 0)
	{
		flogg(critical) << "Cannot resolve hostname" << endl;
		return 1;
	}

	flogg(info) << "Connecting to " << s.getSocket().getResolvedServerName() << endl;
	if (s.open() != 0)
	{
		flogg(critical) << "Failed to connect to host : " << strerror(errno) << endl;
		return 1;
	}

	flogg(debug) << "Connection successful !" << endl;


	pts02Handshake h("Secharpizbad");
	pts01Login l(23, "Secharpizbad");
	ptsFEPing p;

	s << l;

	bool notKicked = true;
	while (notKicked)
	{
		if (s.queue_size())
		{
			McPacketFromServer *pfs;
			s >> pfs;

			switch (pfs->getPacketId())
			{
				case 0x01:
				{
					pfs01Login *login = (pfs01Login*)pfs;

					flogg(debug) << "Login request accepted" << endl;
					flogg(debug) << "   . Player entity: " << login->getPid() << endl;
					flogg(debug) << "   . World seed: " << login->getSeed() << endl;
					flogg(debug) << "   . Max plyers: " << login->getMaxplayers() << endl;
				}
				break;

				case 0x03:
				{
					pfs03ChatMessage *msg = (pfs03ChatMessage*)pfs;

					flogg(debug) << "Message: " << msg->getMessage() << endl;
				}
				break;

				case 0x04:
				{
					pfs04TimeUpdate *time = (pfs04TimeUpdate*)pfs;

					flogg(debug) << "Time update, new time is " << time->getTime()
						<< " ticks" << endl;
				}
				break;

				case 0x06:
				{
					pfs06SpawnPosition *spawn = (pfs06SpawnPosition*)pfs;

					flogg(debug) << "Spawn position is (" << spawn->getX() << ";"
						<< spawn->getY() << ";" << spawn->getZ() << ")"
						<< endl;
				}
				break;

				case 0x32:
				{
					pfs32PreChunk *pchunk = (pfs32PreChunk*)pfs;
					flogg(debug) << "Chunk to ";

					if (pchunk->getMode())
						mclog << "load";
					else
						mclog << "unload";

					mclog << " at " << pchunk->getX() << ";" << pchunk->getZ() << endl;
				}
				break;


				case 0x33:
				{
					pfs33MapChunk *pchunk = (pfs33MapChunk*)pfs;
					flogg(debug) << "Chunk at " << pchunk->getX() << ";" << pchunk->getY()
							<< ";" << pchunk->getZ() << " size: "
							<< pchunk->getSizex() << ";" << pchunk->getSizey()
							<< ";" << pchunk->getSizez() << " data size: "
							<< pchunk->getSize() << " / " << pchunk->getData().size()
							<< endl;
				}
				break;

				case 0x82:
				{
					pfs82UpdateSign *sign = (pfs82UpdateSign*)pfs;
					flogg(debug) << "Sign at ("
						<< sign->getX() << ";" << sign->getY() << ";" << sign->getZ() << ") - "
						<< sign->getText1() << " / " << sign->getText2() << " / "
						<< sign->getText3() << " / " << sign->getText4() << endl;
				}
				break;

				case 0xFF:
				{
					pfsFFKick *kick = (pfsFFKick*)pfs;

					flogg(debug) << "Kicked ! Reason: " << kick->getReason() << endl;
					notKicked = false;
				}
				break;
			}

			delete pfs;
		}
		else
		{
			if (!s.isAlive())
			{
				flogg(critical) << "Packet thread is dead, stopping." << logg::endl;
				notKicked = false;
			}
			else
				usleep(10000);
		}
	}
	s.close();*/

	vector3d v = { 0, 0, 0 };
	vector3f vf;
	flogg(debug) << "sizeof vect3d=" << sizeof(vector3d) << " (" << sizeof(v) << ")" << logg::endl;
	flogg(debug) << "sizeof vect3f=" << sizeof(vector3f) << " (" << sizeof(vf) << ")" << logg::endl;
	return 0;
}
